{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Layout of Jupyter widgets\n", "\n", "This notebook presents how to layout Jupyter interactive widgets to build rich and *reactive* widget-based applications." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can jump directly to these sections:\n", "\n", "+ [The layout attribute](#The-layout-attribute)\n", "+ [The Flexbox layout](#The-Flexbox-layout)\n", "+ [The Grid layout](#The-Grid-layout)\n", "+ [Image layout and sizing](#Image-layout-and-sizing)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## The `layout` attribute\n", "\n", "Jupyter interactive widgets have a `layout` attribute exposing a number of CSS properties that impact how widgets are laid out.\n", "\n", "### Exposed CSS properties\n", "\n", "
object_fit
with large image{size}>'.format(size=caption_size))\n",
"vb.layout.align_items = 'center'\n",
"hb = HBox()\n",
"hb.layout = hbox_layout\n",
"hb.children = boxes\n",
"\n",
"vb.children = [h, hb]\n",
"vb"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### `object_fit` in a `Box` larger than the original image\n",
"\n",
"The effect of each can be seen in the image below. In each case, the image is in a box with a green border. The original image is 50x25 and the grid boxes in the image are squares."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"with open('images/gaussian_with_grid_tiny.png', 'rb') as f:\n",
" im_50_25 = f.read()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"boxes = []\n",
"for fit in fit_options:\n",
" ib = Image(value=im_50_25)\n",
" ib.layout.object_fit = fit\n",
" ib.layout.margin = image_margin\n",
" boxes.append(make_box_for_grid(ib, fit))\n",
"\n",
"vb = VBox()\n",
"h = HTML(value='<{size}>Examples of object_fit
with small image{size}>'.format(size=caption_size))\n",
"vb.layout.align_items = 'center'\n",
"hb = HBox()\n",
"hb.layout = hbox_layout\n",
"hb.children = boxes\n",
"\n",
"vb.children = [h, hb]\n",
"vb"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"It may be surprising, given the description of the values for `option_fit`, that in none of the cases does the image actually fill the box. The reason is that the underlying image is only 50 pixels wide, half the width of the box, so `fill` and `cover` mean \"fill/cover the content box determined by the size of the image\".\n",
"\n",
"### `object_fit` in a `Box` larger than the original image: use image layout width `100%` to fill container\n",
"\n",
"If the width of the image's layout is set to `100%` it will fill the box in which it is placed. This example also illustrates the difference between `'contain'` and `'scale-down'`. The effect of `'scale-down'` is either the same as `'contain'` or `'none'`, whichever leads to the smaller displayed image. In this case, the smaller image comes from doing no fitting, so that is what is displayed."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"boxes = []\n",
"for fit in fit_options:\n",
" ib = Image(value=im_50_25)\n",
" ib.layout.object_fit = fit\n",
" ib.layout.margin = image_margin\n",
"\n",
" # NOTE WIDTH IS SET TO 100%\n",
" ib.layout.width = '100%'\n",
" \n",
" boxes.append(make_box_for_grid(ib, fit))\n",
"\n",
"vb = VBox()\n",
"h = HTML(value='<{size}>Examples of object_fit
with image '\n",
" 'smaller than container{size}>'.format(size=caption_size))\n",
"vb.layout.align_items = 'center'\n",
"hb = HBox()\n",
"hb.layout = hbox_layout\n",
"hb.children = boxes\n",
"\n",
"vb.children = [h, hb]\n",
"vb"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Examples of `object_position`\n",
"\n",
"There are several ways to set object position:\n",
"\n",
"+ Use keywords like `top` and `left` to describe how the image should be placed in the container.\n",
"+ Use two positions, in pixels, for the offset from the top, left corner of the container to the top, left corner of the image. The offset may be positive or negative, and can be used to position the image outside of the box.\n",
"+ Use a percentage for the offset in each direction. The percentage is a the fraction of the vertical or horizontal *whitespace* around the image if the image is smaller than the container, or the portion of the image outside the container if the image is larger than the container.\n",
"+ A mix of pixel and percent offsets.\n",
"+ A mix of keywords and offsets.\n",
"\n",
"Image scaling as determined by `object_fit` will take precedence over the positioning in some cases. For example, if `object_fit` is `fill`, so that the image is supposed to fill the container without preserving the aspect ratio, then `object_position` will have no effect because there is effectively no positioning to do. \n",
"\n",
"Another way to think about it is this: `object_position` specifies how the *white space* around an image should be distributed in a container if there is white space in a particular direction. "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Specifying `object_position` with keywords \n",
"\n",
"This form of `object_position` takes two keywords, one for horizontal position of the image in the container and one for the vertical position, in that order. \n",
"\n",
"+ The horizontal position must be one of: \n",
" * `'left'`: the left side of the image should be aligned with the left side of the container\n",
" * `'center'`: the image should be centered horizontally in the container.\n",
" * `'right'`: the right side of the image should be aligned with the right side of the container.\n",
"+ The vertical position must be one of\n",
" * `'top'`: the top of the image should be aligned with the top of the container.\n",
" * '`center`': the image should be centered vertically in the container. \n",
" * `'bottom'`: the bottom of the image should be aligned with the bottom of the container.\n",
" \n",
"The effect of each is display below, once for an image smaller than the container and once for an image larger than the container. \n",
"\n",
"In the examples below the `object_fit` is set to `'none'` so that the image is not scaled."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"object_fit = 'none'\n",
"image_value = [im_600_300, im_50_25]\n",
"horz_keywords = ['left', 'center', 'right']\n",
"vert_keywords = ['top', 'center', 'bottom']\n",
"\n",
"rows = []\n",
"for image, caption in zip(image_value, ['600 x 300 image', '50 x 25 image']):\n",
" cols = []\n",
" for horz in horz_keywords:\n",
" for vert in vert_keywords:\n",
" ib = Image(value=image)\n",
" ib.layout.object_position = '{horz} {vert}'.format(horz=horz, vert=vert)\n",
" ib.layout.margin = image_margin\n",
" ib.layout.object_fit = object_fit\n",
" # ib.layout.height = 'inherit'\n",
" ib.layout.width = '100%'\n",
" cols.append(make_box_for_grid(ib, ib.layout.object_position))\n",
" hb = HBox()\n",
" hb.layout = hbox_layout\n",
" hb.children = cols\n",
" rows.append(hb)\n",
"\n",
"vb = VBox()\n",
"\n",
"h1 = HTML(value='<{size}> object_position
by '\n",
" 'keyword with large image{size}>'.format(size=caption_size))\n",
"h2 = HTML(value='<{size}> object_position
by '\n",
" 'keyword with small image{size}>'.format(size=caption_size))\n",
"\n",
"vb.children = [h1, rows[0], h2, rows[1]]\n",
"vb.layout.height = '400px'\n",
"vb.layout.justify_content = 'space-around'\n",
"vb.layout.align_items = 'center'\n",
"vb"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Specifying `object_position` with offsets in pixels\n",
"\n",
"One can specify the offset of the top, left corner of the image from the top, left corner of the container in pixels. The first of the two offsets is horizontal, the second is vertical and either may be negative. Using a large enough offset that the image is outside the container will result in the image being hidden.\n",
"\n",
"The image is scaled first using the value of `object_fit` (which defaults to `fill` if nothing is specified) then the offset is applied.\n",
"\n",
"Offsets can be specified from the bottom and/or right side by combining keywords and pixel offsets. For example, `right 10px bottom 20px` offsets the right side of the image 10px from the right edge of the container and the image bottom 20px from the bottom of the container."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"object_fit = ['none', 'contain', 'fill', 'cover']\n",
"offset = '20px 10px'\n",
"image_value = [im_600_300]\n",
"\n",
"boxes = []\n",
"for image, caption in zip(image_value, ['600 x 300 image', ]):\n",
" for fit in object_fit:\n",
" ib = Image(value=image)\n",
" ib.layout.object_position = offset\n",
" ib.layout.margin = image_margin\n",
" ib.layout.object_fit = fit\n",
" # ib.layout.height = 'inherit'\n",
" ib.layout.width = '100%'\n",
" title = 'object_fit: {}'.format(ib.layout.object_fit)\n",
" boxes.append(make_box_for_grid(ib, title))\n",
"\n",
"vb = VBox()\n",
"h = HTML(value='<{size}>object_position
by '\n",
" 'offset {offset} with several '\n",
" 'object_fit
s with large image{size}>'.format(size=caption_size,\n",
" offset=offset))\n",
"vb.layout.align_items = 'center'\n",
"hb = HBox()\n",
"hb.layout = hbox_layout\n",
"hb.children = boxes\n",
"\n",
"vb.children = [h, hb]\n",
"vb"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Specifying `object_position` with offsets as a percentage\n",
"\n",
"One can specify the offset of the top, left corner of the image from the top, left corner of the container as a percent.The first of the two offsets is horizontal, the second is vertical and either may be negative. Using a large enough offset that the image is outside the container will result in the image being hidden. \n",
"\n",
"The important thing to understand is that this is a percent of the *white space* in each direction if the image is smaller than the container, so that `50% 50%` centers the image. \n",
"\n",
"If the image is larger than the container after scaling using the `object_fit`, then the offset is a percentage of the overflow of the image outside the container. That means that `50% 50%` also centers an image *larger* than the container. A value of `10% 90%` would put 10% of the out-of-container part of the image left of the left edge and 90% of the out-of-container part vertically above the top edge.\n",
"\n",
"As with specifying the `object_position` by keywords, the `object_fit` can prevent any offset from being applied to the image."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.0"
}
},
"nbformat": 4,
"nbformat_minor": 4
}